#include "ws2812_dma.h"
#include <string.h>
#include <math.h>
#include <stdlib.h>

// 内部函数声明
static void WS2812_Encode(WS2812_Controller *controller);

static uint32_t RGB_SHOW_NOW_1[LED_COUNT];
static uint8_t RGB_SHOW_NOW_2[LED_COUNT * 24];


/**
 * @brief 初始化 WS2812 控制器
 * @param controller: WS2812 控制器实例指针
 * @param hspi: SPI 句柄指针
 * @param data_port: 数据引脚 GPIO 端口
 * @param data_pin: 数据引脚编号
 * @param led_count: LED 数量
 * @return HAL 状态
 */
HAL_StatusTypeDef WS2812_Init(WS2812_Controller *controller, SPI_HandleTypeDef *hspi,
                              GPIO_TypeDef *data_port, uint16_t data_pin, uint16_t led_count)
{
    // 初始化控制器基本参数
    controller->hspi = hspi;
    controller->data_port = data_port;
    controller->data_pin = data_pin;
    controller->led_count = led_count;
    controller->brightness = 255; // 默认最大亮度
    controller->is_transmitting = 0;

    // 计算缓冲区大小并分配内存
    controller->frame_buffer = RGB_SHOW_NOW_1;

    if (controller->frame_buffer == NULL)
        return HAL_ERROR;

    controller->dma_buffer_size = led_count * 24; // 每个LED需要24字节SPI数据
    controller->dma_buffer = RGB_SHOW_NOW_2;//(uint8_t *)malloc(controller->dma_buffer_size);
    if (controller->dma_buffer == NULL)
    {
        free(controller->frame_buffer);
        return HAL_ERROR;
    }

    // 初始化缓冲区
    WS2812_Clear(controller);

    return HAL_OK;
}

/**
 * @brief 设置指定位置LED的颜色
 * @param controller: WS2812 控制器实例指针
 * @param index: LED索引（从0开始）
 * @param color: 颜色值（GRB格式，0x00RRGGBB）
 */
void WS2812_SetPixel(WS2812_Controller *controller, uint16_t index, uint32_t color)
{
    if (index >= controller->led_count)
        return;

    // 应用亮度调节
    uint8_t r = (color >> 16) & 0xFF;
    uint8_t g = (color >> 8) & 0xFF;
    uint8_t b = color & 0xFF;

    r = (r * controller->brightness) / 255;
    g = (g * controller->brightness) / 255;
    b = (b * controller->brightness) / 255;

    controller->frame_buffer[index] = (r << 16) | (g << 8) | b;
}

/**
 * @brief 清空所有LED（设置为黑色）
 * @param controller: WS2812 控制器实例指针
 */
void WS2812_Clear(WS2812_Controller *controller)
{
    for (int i = 0; i < LED_COUNT; i++)
    {
        controller->frame_buffer[i] = 0;
    }
    // memset(controller->frame_buffer, 0, controller->led_count * sizeof(uint32_t));
}

// uint8_t data_test[240] = {0};
/**
 * @brief 将帧缓冲区的数据发送到灯带
 * @param controller: WS2812 控制器实例指针
 */
void WS2812_Show(WS2812_Controller *controller)
{
    // 如果正在传输，则等待上一次传输完成
    // while (controller->is_transmitting)
    //     ;

    // 将颜色数据编码为SPI时序数据
    WS2812_Encode(controller);


    // 启动DMA传输
    controller->is_transmitting = 1;
    HAL_SPI_Transmit_DMA(controller->hspi, controller->dma_buffer, controller->dma_buffer_size);
    // HAL_SPI_Transmit_DMA(controller->hspi, data_test, 240);
}

/**
 * @brief 设置整体亮度
 * @param controller: WS2812 控制器实例指针
 * @param brightness: 亮度值（0-255）
 */
void WS2812_SetBrightness(WS2812_Controller *controller, uint8_t brightness)
{
    controller->brightness = brightness;
}

/**
 * @brief 获取指定位置LED的颜色
 * @param controller: WS2812 控制器实例指针
 * @param index: LED索引（从0开始）
 * @return 颜色值（GRB格式）
 */
uint32_t WS2812_GetPixel(WS2812_Controller *controller, uint16_t index)
{
    if (index >= controller->led_count)
        return 0;
    return controller->frame_buffer[index];
}

/**
 * @brief 将HSV颜色转换为GRB颜色
 * @param h: 色相（0-255）
 * @param s: 饱和度（0-255）
 * @param v: 明度（0-255）
 * @return GRB格式颜色值
 */
uint32_t WS2812_HSVToColor(uint8_t h, uint8_t s, uint8_t v)
{
    if (s == 0)
    {
        // 灰度
        return (v << 16) | (v << 8) | v;
    }

    uint8_t region = h / 43;
    uint8_t remainder = (h % 43) * 6;

    uint8_t p = (v * (255 - s)) >> 8;
    uint8_t q = (v * (255 - ((s * remainder) >> 8))) >> 8;
    uint8_t t = (v * (255 - ((s * (255 - remainder)) >> 8))) >> 8;

    switch (region)
    {
    case 0:
        return (v << 16) | (t << 8) | p;
    case 1:
        return (q << 16) | (v << 8) | p;
    case 2:
        return (p << 16) | (v << 8) | t;
    case 3:
        return (p << 16) | (q << 8) | v;
    case 4:
        return (t << 16) | (p << 8) | v;
    default:
        return (v << 16) | (p << 8) | q;
    }
}

/**
 * @brief 将帧缓冲区的颜色数据编码为SPI时序数据
 * @param controller: WS2812 控制器实例指针
 */
static void WS2812_Encode(WS2812_Controller *controller)
{
    for (uint16_t i = 0; i < controller->led_count; i++)
    {
        uint32_t color = controller->frame_buffer[i];

        // WS2812使用GRB格式，每个颜色通道8位
        uint8_t g = (color >> 8) & 0xFF;  // 绿色
        uint8_t r = (color >> 16) & 0xFF; // 红色
        uint8_t b = color & 0xFF;         // 蓝色

        // 编码每个颜色通道的8位数据（高位在前）
        for (uint8_t bit = 0; bit < 8; bit++)
        {
            controller->dma_buffer[i * 24 + bit] = (g & (1 << (7 - bit))) ? WS2812_BIT_1 : WS2812_BIT_0;
            controller->dma_buffer[i * 24 + 8 + bit] = (r & (1 << (7 - bit))) ? WS2812_BIT_1 : WS2812_BIT_0;
            controller->dma_buffer[i * 24 + 16 + bit] = (b & (1 << (7 - bit))) ? WS2812_BIT_1 : WS2812_BIT_0;
        }
    }
}
